<?php

namespace WhaleIot\mqtt\libs;

class Message
{
    /**
     * 端口状态字典
     */
    const PORT_STATUS = [
        0x01 => '端口空闲',
        0x02 => '端口正在使用',
        0x03 => '端口禁用',
        0x04 => '端口故障',
        0x05 => '端口浮充',
    ];
    /**
     * 结束订单的类型
     */
    const STOP_TYPE = [
        0X00 => '所有类型的订单',
        0X01 => '远程支付订单',
        0X02 => '本地的支付订单',
    ];
    /**
     * 结束原因
     */
    const STOP_REASON = [
        0X00 => '购买的充电时或者电量用完了',
        0X01 => '用户手动停止（拔插头，或是按了停止按钮）',
        0X02 => '充电满了，自动停止',
        0X03 => '超功率自停',
        0X04 => '远程断电',
        0X0B => '设备或是端口出现问题，被迫停止',
    ];
    /**
     * 开启说明
     */
    const START_RESULT = [
        0X01 => '成功',
        0X02 => '不支持此种模式',
        0X0B => '充电站故障',
        0X0C => '端口已经被使用',
    ];
    /**
     * 开启原因
     */
    const CHARGE_TYPE = [
        0X01 => '投币',
        0X02 => '刷卡',
        0X03 => '远程启动',
        0X04 => '其他原因',
    ];
    /**
     * IC卡
     */
    const IC_CARD_TYPE = [
        0X00 => '扣费成功',
        0X01 => '余额不足',
        0X02 => '非法卡',
    ];
    /**
     * 异常字典
     */
    const ERROR_ENUM = [
        0xA0 => '停止充电异常，继电器粘连、短路',
        0xA1 => '高温异常',
        0x21 => '高温恢复正常',
        0xA2 => '低温异常',
        0x22 => '低温恢复正常',
        0xA3 => '空载，充电头脱落、充电器拔出',
        0x23 => '负载恢复正常',
        0xA4 => '消防（烟感）',
        0x24 => '消防（烟感）恢复正常',
        0xA5 => '过载',
        0x25 => '过载恢复正常',
        0xA6 => '倾斜',
        0x26 => '倾斜恢复正常',
        0xA7 => '水压高',
        0x27 => '水压（从高）恢复正常',
        0xA8 => '水压低',
        0x28 => '水压（从低）恢复正常',
        0xA9 => '过压',
        0x29 => '过压恢复正常',
        0xAA => '欠压',
        0x2A => '欠压恢复正常',
        0xAB => '预留1发生异常',
        0x2B => '预留1恢复正常',
        0xAC => '预留2发生异常',
        0x2C => '预留2恢复正常',
    ];

    const SYSTEM_ENUM  = [
        'coin_min'    => [
            'info' => '设置投币充电时间',
            'unit' => '分钟'
        ],
        'card_min'    => [
            'info' => '设置刷卡充电时间',
            'unit' => '分钟'
        ],
        'coin_elec'   => [
            'info' => '设置单次投币最大用电量',
            'unit' => '（0.1度）'
        ],
        'card_elec'   => [
            'info' => '设置单次刷卡最大用电量',
            'unit' => '（0.1度）'
        ],
        'cst'         => [
            'info' => '设置刷卡扣费金额',
            'unit' => '角'
        ],
        'power_max_1' => [
            'info' => '设置第一档最大充电功率',
            'unit' => '瓦'
        ],

        'power_max_2'      => [
            'info' => '设置第二档最大充电功率',
            'unit' => '瓦'
        ],
        'power_max_3'      => [
            'info' => '设置第三档最大充电功率',
            'unit' => '瓦'
        ],
        'power_max_4'      => [
            'info' => '设置第四档最大充电功率',
            'unit' => '瓦'
        ],
        'power_2_time'     => [
            'info' => '设置第二档充电时间百分比',
            'unit' => '%'
        ],
        'power_3_time'     => [
            'info' => '设置第三档充电时间百分比',
            'unit' => '%'
        ],
        'power_4_time'     => [
            'info' => '设置第四档充电时间百分比',
            'unit' => '%'
        ],
        'sp_rec_mon'       => [
            'info' => '是否支持余额回收',
            'unit' => ''
        ],
        'sp_full_empty'    => [
            'info' => '是否支持断电自停',
            'unit' => ''
        ],
        'full_power_min'   => [
            'info' => '设置充电器最大浮充功率',
            'unit' => '瓦'
        ],
        'full_charge_time' => [
            'info' => '设置浮充时间',
            'unit' => '分钟'
        ],
        'elec_time_first'  => [
            'info' => '是否初始显示电量',
            'unit' => ''
        ],
    ];
    const SYSTEM2_ENUM = [
        'low_power'            => [
            'info' => '设置空载检测功率',
            'unit' => '瓦'
        ],
        'max_total_time'       => [
            'info' => '设置单次充电最大时长',
            'unit' => '（10分钟）'
        ],
        'over_voltage'         => [
            'info' => '设置过压值',
            'unit' => 'V'
        ],
        'low_voltage'          => [
            'info' => '设置欠压值',
            'unit' => 'V'
        ],
        'over_temp'            => [
            'info' => '高温告警阈值',
            'unit' => '℃'
        ],
        'over_temp_delay_time' => [
            'info' => '高温告警后断电的延时时间',
            'unit' => '分钟'
        ],
        'time_disp_on'         => [
            'info' => '显示开启时间',
            'unit' => ''
        ],
        'time_disp_off'        => [
            'info' => '显示关闭时间',
            'unit' => ''
        ],
        'price_power_1'        => [
            'info' => '第一档单价',
            'unit' => '（0.001/小时）'
        ],
        'price_power_2'        => [
            'info' => '第二档单价',
            'unit' => '（0.001/小时）'
        ],
        'price_power_3'        => [
            'info' => '第三档单价',
            'unit' => '（0.001/小时）'
        ],
        'price_power_4'        => [
            'info' => '第四档单价',
            'unit' => '（0.001/小时）'
        ],
        'price_power_5'        => [
            'info' => '第五档单价',
            'unit' => '（0.001/小时）'
        ],
        'low_power_check_time' => [
            'info' => '设置启动充电时空载检测时间',
            'unit' => '秒'
        ],
        'stop_delay_time'      => [
            'info' => '设置充电过程中空载检测时间',
            'unit' => '秒'
        ],
        'max_total_power'      => [
            'info' => '最大总功率',
            'unit' => '百瓦'
        ],
    ];

    /**
     * 注释:Json转报文
     * 创建者:JSL
     * 时间:2023/06/28 028 下午 02:03
     * @param array $data
     * @return array
     */
    public static function setDatasource(array $data): array
    {
        $param = $data['param'];
        switch ($data['cmd']) {
            case 0x01://查询充电站端口总数
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '查询充电站端口总数（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x02: //查询所有空闲(可用)的充电站端口
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '查询所有空闲(可用)的充电站端口（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x07://查询消费总额数据
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '查询消费总额数据（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x0A: //回复上传设备故障
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '上传设备故障（平台回复）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x0F: //读取设备每个端口的状态
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '读取设备每个端口的状态（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x1E: //读取设备系统参数
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '读取设备系统参数（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x20://回复上报投币打开的信息
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '上报投币打开的信息（平台回复）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x21://上传端口的实时状态
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '上传端口的实时状态（平台回复）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x23://参数读取2
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '参数读取2（平台发送）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0xA2://设备心跳
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '设备心跳（平台回复）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0xA1://上线登录
                $dec = [
                    $param['state'] ?? 0
                ];
                $log = [
                    '上线登录（平台回复）',
                    '状态值：' . $dec[0]
                ];
                break;
            case 0x09://设置IC卡、投币器是否可用
                $dec = [
                    $param['coin'],
                    $param['ic']
                ];
                $log = [
                    '设置IC卡、投币器是否可用（平台发送）',
                    '投币设置：' . ($param['coin'] == 1 ? '可用' : '不可用'),
                    '刷卡设置：' . ($param['ic'] == 1 ? '可用' : '不可用'),
                ];
                break;
            case 0x0C://锁定、解锁某一个端口
                $dec = [
                    $param['port'],
                    $param['status']
                ];
                $log = [
                    '锁定或者解锁某一个端口（平台发送）',
                    '端口号：' . $param['port'],
                    '状态设置：' . ($param['status'] == 1 ? '解锁' : '锁定'),
                ];
                break;
            case 0x0D://远程停止某个端口的充电
                $dec = [
                    $param['port'],
                    $param['type']
                ];
                $log = [
                    '远程停止某个端口的充电（平台发送）',
                    '端口号：' . $param['port'],
                    '订单的支付类型：' . (self::STOP_TYPE[$param['type']] ?? 'code') . $param['type'],
                ];
                break;
            case 0x18://设置系统参数
                $dec = [
                    floor($param['coin_min'] / 256),
                    $param['coin_min'] % 256,

                    floor($param['card_min'] / 256),
                    $param['card_min'] % 256,

                    $param['coin_elec'],
                    $param['card_elec'],
                    $param['cst'],

                    floor($param['power_max_1'] / 256),
                    $param['power_max_1'] % 256,

                    floor($param['power_max_2'] / 256),
                    $param['power_max_2'] % 256,

                    floor($param['power_max_3'] / 256),
                    $param['power_max_3'] % 256,

                    floor($param['power_max_4'] / 256),
                    $param['power_max_4'] % 256,

                    $param['power_2_time'],
                    $param['power_3_time'],
                    $param['power_4_time'],
                    $param['sp_rec_mon'],
                    $param['sp_full_empty'],
                    $param['full_power_min'],
                    $param['full_charge_time'],
                    $param['elec_time_first'],
                ];
                $log = [
                    '设置系统参数（平台发送）'
                ];
                foreach ($param as $key => $value) {
                    $log[] = isset(self::SYSTEM_ENUM[$key]) ? (self::SYSTEM_ENUM[$key]['info'] . '：' . $value . self::SYSTEM_ENUM[$key]['unit'] ): ($key . '：' . $value);
                }
                break;
            case 0x10://回复在线刷卡
                $dec = [
                    $param['res'],

                    floor($param['card_surp'] * 10 / 256),
                    ($param['card_surp'] * 10) % 256,
                ];
                $log = [
                    '在线刷卡（平台回复）',
                    '刷卡状态：' . (self::IC_CARD_TYPE[$param['res']] ?? ('未知状态:code' . $param['res'])),
                    'IC卡余额：' . $param['card_surp'] . '元',
                ];
                break;
            case 0x15://查询当前的充电状态
                $dec = [
                    $param['port'],
                ];
                $log = [
                    '查询当前的充电状态（平台发送）',
                    '端口号：' . $param['port']
                ];
                break;
            case 0x16://回复充电结束
                $dec = [
                    $param['port'],
                ];
                $log = [
                    '充电结束（平台回复）',
                    '端口号：' . $param['port']
                ];
                break;
            case 0x14://用户付款成功，开始充电
                $dec = [
                    $param['port'],

                    floor($param['money'] * 10 / 256),
                    ($param['money'] * 10) % 256,

                    floor($param['time'] / 256),
                    $param['time'] % 256,

                    floor($param['elec'] * 100 / 256),
                    ($param['elec'] * 100) % 256
                ];
                $log = [
                    '启动充电（平台发送）',
                    '金额：' . $param['money'] . '元',
                    '时间：' . $param['time'] . '分钟',
                    '电量：' . $param['elec'] . '度',
                ];
                break;
            case 0x22://参数设置2
                $time_disp_on  = explode(':', $param['time_disp_on']);
                $time_disp_off = explode(':', $param['time_disp_off']);
                $dec           = [
                    $param['low_power'],
                    $param['max_total_time'],

                    floor($param['over_voltage'] / 256),
                    $param['over_voltage'] % 256,

                    floor($param['low_voltage'] / 256),
                    $param['low_voltage'] % 256,

                    $param['over_temp'],
                    $param['over_temp_delay_time'],

                    hexdec($time_disp_on[0]),
                    hexdec($time_disp_on[1]),

                    hexdec($time_disp_off[0]),
                    hexdec($time_disp_off[1]),

                    floor($param['price_power_1'] / 256),
                    $param['price_power_1'] % 256,

                    floor($param['price_power_2'] / 256),
                    $param['price_power_2'] % 256,

                    floor($param['price_power_3'] / 256),
                    $param['price_power_3'] % 256,

                    floor($param['price_power_4'] / 256),
                    $param['price_power_4'] % 256,

                    floor($param['price_power_5'] / 256),
                    $param['price_power_5'] % 256,

                    floor($param['low_power_check_time'] / 256),
                    $param['low_power_check_time'] % 256,

                    floor($param['stop_delay_time'] / 256),
                    $param['stop_delay_time'] % 256,

                    floor($param['max_total_power'] / 256),
                    $param['max_total_power'] % 256,
                ];
                $log           = [
                    '参数设置2（平台发送）',
                ];
                foreach ($param as $key => $value) {
                    $log[] = isset(self::SYSTEM2_ENUM[$key]) ? (self::SYSTEM2_ENUM[$key]['info'] . '：' . $value . self::SYSTEM2_ENUM[$key]['unit'] ): ($key . '：' . $value);
                }
                break;
            case 0x24://音量设置
                $dec = [
                    $param['volume']
                ];
                $log = [
                    '音量设置（平台发送）',
                    '音量：' . $param['volume']
                ];
                break;
            case 0x31://借用开柜
                $dec = [
                    $param['port']
                ];
                $log = [
                    '借用开柜（平台发送）',
                    '端口号：' . $param['port']
                ];
                break;
            case 0x32://归还开柜
                $dec = [
                    $param['port']
                ];
                $log = [
                    '归还开柜（平台发送）',
                    '端口号：' . $param['port']
                ];
                break;
            case 0x34://强制开门
                $dec = [
                    $param['port']
                ];
                $log = [
                    '强制开门（平台发送）',
                    '端口号：' . $param['port']
                ];
                break;
            default://自定义指令 请直接发送十进制字节
                $dec = $param;
                $hex = [];
                foreach ($dec as $value) {
                    $value = dechex($value);
                    if (strlen($value) == 1) {
                        $value = '0' . $value;
                    }
                    $hex[] = $value;
                }
                $log = [
                    '自定义指令（' . $data['cmd'] . '）',
                    'DEC：' . implode(' ', $dec),
                    'HEX：' . implode(' ', $hex)
                ];
                break;
        }
        $sop    = $data['sop'] ?? 0xAA;
        $cmd    = $data['cmd'];
        $len    = count($dec) + 3;
        $result = 0x01;
        $sum    = $len ^ $data['cmd'] ^ $result;
        $msg    = chr($sop); //SOP 单字节字头 固定AA
        $msg    .= chr($len);
        $msg    .= chr($cmd); //CMD 单字节 命令
        $msg    .= chr($result);
        foreach ($dec as $item) {
            $msg .= chr($item);
            $sum = $sum ^ $item;
        }
        $msg .= chr($sum);
        //解析报文
        list($hex) = self::mimeMessages($msg);
        return [$msg, $hex, self::formattingLog($log), $log[0]];
    }

    /**
     * 注释:报文转Json
     * 创建者:JSL
     * 时间:2023/06/25 025 上午 11:18
     * @param string $imei
     * @param array $hex
     * @param array $dec
     * @return array
     */
    public static function getDatasource(string $imei, array $hex, array $dec): array
    {

        $cmd = $dec[2];
        switch ($cmd) {

            case 0x01: //查询充电站端口总数
                $param = [
                    'port_num'   => $dec[4],
                    'start_item' => $dec[5],
                ];
                $log   = [
                    '查询充电站端口总数（设备回复）',
                    '设备端口数量：' . $dec[4],
                    '第一个端口的名称：' . $dec[5],
                ];
                break;

            case 0x02://查询所有空闲(可用)的充电站端口
                $port_num = $dec[4];
                $list     = [];
                if ($port_num > 0) {
                    //去掉前5个参数 然后每个端口会占用1个 取出所有端口数据 再加工
                    array_splice($dec, 0, 5);//移除前五个元素
                    array_pop($dec);
                    $list = $dec;
                }
                $param = [
                    'port_num' => $port_num,
                    'list'     => $list,
                ];
                $log   = [
                    '查询所有空闲(可用)的充电站端口（设备回复）',
                    '设备空闲端口数量：' . $port_num,
                    '空闲的端口：' . implode('、', $list)
                ];
                break;

            case 0x07://查询消费总额数据
                $param = [
                    'card_money' => ($dec[4] * 256 + $dec[5]) / 10,
                    'coin_money' => ($dec[6] * 256 + $dec[6]) / 10,
                ];
                $log   = [
                    '查询消费总额数据（设备回复）',
                    '机器消费刷卡总金额：' . $param['card_money'] . '元',
                    '机器消费投币总金额：' . $param['coin_money'] . '元'
                ];
                break;

            case 0x09://设置 IC 卡、投币器是否可用
                $param = [
                    'state' => $dec[4]
                ];
                $log   = [
                    '设置IC卡、投币器是否可用（设备回复）',
                    'IC卡、投币器设置成功！'
                ];
                break;

            case 0x0A://上传设备故障
                $param = [
                    'port'       => $dec[4],
                    'error_code' => $dec[5],
                ];
                $error = self::ERROR_ENUM[$dec[5]] ?? ('未知故障:code' . $dec[5]);
                $log   = [
                    '上传设备故障（设备上报）',
                    '设备上报故障：' . ($dec[4] == 0xFF ? '设备' : $dec[4] . '号端口') . $error
                ];
                break;

            case 0x0B://获取系统时间
                $param = [
                    'state' => $dec[4],
                ];
                $log   = [
                    '获取系统时间（设备上报）',
                ];
                break;

            case 0x0C://锁定或者解锁某一个端口
                $param = [
                    'port' => $dec[4],
                ];
                $log   = [
                    '锁定或者解锁某一个端口（设备回复）',
                    '锁定或者解锁了' . $dec['4'] . '端口'
                ];
                break;
            case 0x0D://远程停止某个端口的充电
                $param = [
                    'port' => $dec[4],
                    'time' => ($dec[5] * 256 + $dec[6])
                ];
                $log   = [
                    '远程停止某个端口的充电（设备回复）',
                    '停止充电端口：' . $param['port'],
                    '充电时间：' . $param['time'] . '分钟',
                ];
                break;
            case 0x0F://读取设备每个端口的状态
                $port_num = $dec[4];
                //去掉前5个参数 然后每个端口会占用8个 取出所有端口数据 再加工
                array_splice($dec, 0, 5);//移除前五个元素
                array_pop($dec);
                $chunk = array_chunk($dec, 2);
                $list  = [];
                foreach ($chunk as $key => $value) {
                    $list[$key] = [
                        'port'   => $value[0],
                        'status' => $value[1],
                    ];
                }
                $param = [
                    'port_num' => $port_num,
                    'list'     => $list
                ];
                $log   = [
                    '读取设备每个端口的状态（设备回复）',
                ];
                foreach ($list as $value) {
                    $status = self::PORT_STATUS[$value['status']] ?? ('未知状态:code' . $value['status']);
                    $log[]  = $value['port'] . '号端口：状态（' . $status . '）；';
                }

                break;

            case 0x18://设置系统参数
                $param = [
                    'state' => $dec[4],
                ];
                $log   = [
                    '设置系统参数（设备回复）',
                    '设置系统参数成功'
                ];
                break;
            case 0x1E://读取设备系统参数
                array_splice($dec, 0, 4);//移除前4个元素
                $param = [
                    'coin_min'         => $dec[0] * 256 + $dec[1],
                    'card_min'         => $dec[2] * 256 + $dec[3],
                    'coin_elec'        => $dec[4],
                    'card_elec'        => $dec[5],
                    'cst'              => $dec[6],
                    'power_max_1'      => $dec[7] * 256 + $dec[8],
                    'power_max_2'      => $dec[9] * 256 + $dec[10],
                    'power_max_3'      => $dec[11] * 256 + $dec[12],
                    'power_max_4'      => $dec[13] * 256 + $dec[14],
                    'power_2_time'     => $dec[15],
                    'power_3_time'     => $dec[16],
                    'power_4_time'     => $dec[17],
                    'sp_rec_mon'       => $dec[18],
                    'sp_full_empty'    => $dec[19],
                    'full_power_min'   => $dec[20],
                    'full_charge_time' => $dec[21],
                    'elec_time_first'  => $dec[22],
                ];
                $log   = [
                    '读取设备系统参数（设备回复）',
                ];
                foreach ($param as $key => $value) {
                    $log[] = isset(self::SYSTEM_ENUM[$key]) ? (self::SYSTEM_ENUM[$key]['info'] . '：' . $value . self::SYSTEM_ENUM[$key]['unit']) : ($key . '：' . $value);
                }
                break;
            case  0x10://在线卡上传卡号，预扣费
                $param = [
                    'card_id'   => $hex[4] . $hex[5] . $hex[6] . $hex[7],
                    'card_surp' => $dec[8] / 10,
                    'card_ope'  => $dec[9],
                ];
                $log   = [
                    '在线卡上传卡号，预扣费（设备上报）',
                    'IC卡卡号：' . $param['card_id'],
                    '卡片需要改变的金额信息：' . $param['card_surp'] . '元',
                    '操作方式：' . $param['card_ope'] == 1 ? '充值' : '扣费',
                ];
                break;
            case 0x15://查询当前的充电状态
                $param = [
                    'port'  => $dec[4],
                    'time'  => $dec[5] * 256 + $dec[6],
                    'power' => $dec[7] * 256 + $dec[8],
                    'elec'  => ($dec[9] * 256 + $dec[10]) / 100,
                    'surp'  => ($dec[11] * 256 + $dec[12]) / 10,
                ];
                $log   = [
                    '查询当前的充电端口状态（设备回复）',
                    '端口号：' . $param['port'],
                    '剩余时间：' . $param['time'] . '分钟',
                    '充电功率：' . $param['power'] . '瓦',
                    '剩余电量：' . $param['elec'] . '度',
                    '可回收余额：' . $param['surp'] . '元',
                ];
                break;
            case 0x16://提交充电结束状态
                $param = [
                    'port'   => $dec[4],
                    'time'   => $dec[5] * 256 + $dec[6],
                    'elec'   => ($dec[7] * 256 + $dec[8]) / 100,
                    'reason' => $dec[9]
                ];
                $log   = [
                    '充电结束（设备上报）',
                    '端口号：' . $param['port'],
                    '充电时间：' . $param['time'] . '分钟',
                    '充电电量：' . $param['elec'] . '度',
                    '停止的原因：' . (self::STOP_REASON[$param['reason']] ?? ('未知原因:code' . $param['reason'])),
                ];
                break;
            case 0x14://用户付款成功，通知主设备
                $param = [
                    'port'   => $dec[4],
                    'result' => $dec[5]
                ];
                $log   = [
                    '启动设备（设备回复）',
                    '端口号：' . $param['port'],
                    '开启说明：' . (self::START_RESULT[$param['result']] ?? ('未知说明:code' . $param['result'])),
                ];
                break;
            case 0x20://上报投币打开的信息
                $param = [
                    'port'    => $dec[4],
                    'time'    => $dec[5] * 256 + $dec[6],
                    'elec'    => ($dec[7] * 256 + $dec[8]) / 100,
                    'type'    => $dec[9],
                    'money'   => $dec[10],
                    'card_id' => isset($dec[12]) ? $hex[11] . $hex[12] . $hex[13] . $hex[14] : '',
                ];
                $log   = [
                    '上报投币或者刷卡打开的信息（设备上报）',
                    '端口号：' . $param['port'],
                    '充电时间：' . $param['time'] . '分钟',
                    '充电电量：' . $param['elec'] . '度',
                    '充电原因：' . (self::CHARGE_TYPE[$param['type']] ?? ('未知原因:code' . $param['type'])),
                    '付费金额：' . $param['money'] . '元',
                    'IC卡卡号：' . $param['card_id'],
                ];
                break;
            case 0x21://端口状态上报
                $port_num = $dec[4];
                //去掉前5个参数 然后每个端口会占用8个 取出所有端口数据 再加工
                array_splice($dec, 0, 5);//移除前五个元素
                array_pop($dec);
                $chunk = array_chunk($dec, 8);
                $list  = [];
                foreach ($chunk as $key => $value) {
                    $list[$key] = [
                        'port'   => $value[0],
                        'status' => $value[1],
                        'time'   => $value[2] * 256 + $value[3],
                        'power'  => $value[4] * 256 + $value[5],
                        'elec'   => ($value[6] * 256 + $value[7]) / 100,
                    ];
                }
                $param = [
                    'port_num' => $port_num,
                    'list'     => $list
                ];
                $log   = [
                    '端口状态定时上报（设备上报）',
                ];
                foreach ($list as $key => $value) {
                    $status        = self::PORT_STATUS[$value['status']] ??('未知状态:code' . $value['status']);
                    $log[$key + 1] = $value['port'] . '号端口：状态（' . $status . '）；时间：（' . $value['time'] . '分钟）；功率：（' . $value['power'] . '瓦）；电量：（' . $value['elec'] . '度）；';
                }
                break;
            case 0x22://参数设置2
                $param = [
                    'state' => $dec[4],
                ];
                $log   = [
                    '参数设置2（设备回复）',
                    '设置系统参数2成功'
                ];
                break;
            case 0x23://参数读取2
                array_splice($dec, 0, 4);//移除前4个元素
                $param = [
                    'low_power'            => $dec[0],
                    'max_total_time'       => $dec[1],
                    'over_voltage'         => $dec[2] * 256 + $dec[3],
                    'low_voltage'          => $dec[4] * 256 + $dec[5],
                    'over_temp'            => $dec[6],
                    'over_temp_delay_time' => $dec[7],
                    'time_disp_on'         => dechex($dec[8]) . ':' . dechex($dec[9]),
                    'time_disp_off'        => dechex($dec[10]) . ':' . dechex($dec[11]),
                    'price_power_1'        => $dec[12] * 256 + $dec[13],
                    'price_power_2'        => $dec[14] * 256 + $dec[15],
                    'price_power_3'        => $dec[16] * 256 + $dec[17],
                    'price_power_4'        => $dec[18] * 256 + $dec[19],
                    'price_power_5'        => $dec[20] * 256 + $dec[21],
                    'low_power_check_time' => $dec[22] * 256 + $dec[23],
                    'stop_delay_time'      => $dec[24] * 256 + $dec[25],
                    'max_total_power'      => $dec[26] * 256 + $dec[27],
                ];
                $log   = [
                    '参数读取2（设备回复）',
                ];
                foreach ($param as $key => $value) {
                    $log[] = isset(self::SYSTEM2_ENUM[$key]) ? self::SYSTEM2_ENUM[$key]['info'] . '：' . $value . self::SYSTEM2_ENUM[$key]['unit'] : $key . '：' . $value;
                }
                break;
            case 0x24://音量设置
                $param = [
                    'volume' => $dec[4]
                ];
                $log   = [
                    '音量设置（设备回复）',
                    '音量：' . $dec[4]
                ];
                break;
            case 0xA1://设备上线
                array_splice($dec, 0, 4);//移除前4个元素
                array_pop($dec);
                foreach ($dec as &$value) {
                    $value = chr($value);
                }
                $cardNo = implode('', $dec);
                $param  = [
                    'card_no' => $cardNo
                ];
                $log    = [
                    '设备上线（设备上报）',
                    '流量卡号：' . $cardNo
                ];
                break;
            case 0xA2://心跳上报
                $param = [
                    'signal' => $dec[4],
                ];
                $log   = [
                    '心跳上报（设备上报）',
                    '当前信号值：' . $dec[4]
                ];
                break;
            case 0x33://关柜门上报
                $param = [
                    'port' => $dec[4],
                ];
                $log   = [
                    '关柜门上报（设备上报）',
                    '关闭的柜门号：' . $dec[4]
                ];
                break;
            case 0x80://柜门状态

                $status1     = $dec[4];
                $status1     = decbin($status1);
                $status1     = str_pad($status1, 8, "0", STR_PAD_LEFT);
                $status1_arr = str_split($status1);
                $status1_arr = array_reverse($status1_arr);
                if (isset($dec[5])) {
                    $status2     = $dec[5];
                    $status2     = decbin($status2);
                    $status2     = str_pad($status2, 8, "0", STR_PAD_LEFT);
                    $status2_arr = str_split($status2);
                    $status2_arr = array_reverse($status2_arr);
                    $status1_arr = array_merge($status1_arr, $status2_arr);
                }
                $param = [
                    'list' => $status1_arr
                ];
                $log   = [
                    '柜门状态（设备上报）',
                    '柜门状态：' . implode(',', $status1_arr)
                ];
                break;
            default://自定义指令 不做解析 请自行解析
                array_splice($dec, 0, 4);//移除前4个元素
                array_pop($dec);
                array_splice($hex, 0, 4);//移除前4个元素
                array_pop($hex);
                $param = $dec;
                $log   = [
                    '自定义指令（0x' . dechex($cmd) . '）',
                    '参数(dec)：' . implode(' ', $dec),
                    '参数(hex)：' . implode(' ', $hex)
                ];
                break;
        }
        return [$param, self::formattingLog($log), $log[0]];
    }

    /**
     * 注释:解析报文
     * 创建者:JSL
     * 时间:2023/06/25 025 上午 09:52
     * @param string $message 报文原文
     * @return array
     */
    public static function mimeMessages(string $message): array
    {
        //解析报文
        $message = bin2hex($message);
        //转换16进制数组
        $hex = str_split($message, 2);
        $dec = [];
        //生成十进制数组
        foreach ($hex as $value) {
            $dec[] = hexdec($value);
        }

        return [$hex, $dec];
    }

    /**
     * 注释:拼接报文
     * 创建者:JSL
     * 时间:2023/06/25 025 上午 10:28
     * @param string $imei imei
     * @param array $hex 十六进制
     * @param array $dec 十进制
     * @return bool
     */
    public static function spliceMessage(string $imei, array &$hex, array &$dec): bool
    {
        global $globalCache;
        if (count($hex) < 2) {
            return false;
        }
        if ($dec[0] == 170 || $dec[0] == 85) {
            $len = $dec[1] ?? -2;
        } else {
            $len = -2;
        }
        if (count($dec) != $len + 2) {
            $cache = $globalCache[$imei] ?? [
                'dec'    => [],
                'hex'    => [],
                'number' => 0
            ];
            if ($cache['number'] > 10) {
                unset($globalCache[$imei]);
                return false;
            }
            $dec = array_merge($cache['dec'], $dec);
            $hex = array_merge($cache['hex'], $hex);
            $len = $dec[1] ?? 0;
            if (count($dec) != $len + 2) {
                $globalCache[$imei] = ['dec' => $dec, 'hex' => $hex, 'number' => $cache['number']++];
                return false;
            }
        }
        if (isset($globalCache[$imei])) {
            unset($globalCache[$imei]);
        }
        return true;
    }

    /**
     * 注释:验证异或值
     * 创建者:JSL
     * 时间:2022/10/10 9:24
     * @param array $data 十进制
     * @return bool
     */
    public static function checkXorData(array $data): bool
    {
        $sum1 = $data[count($data) - 1];
        array_shift($data);
        array_pop($data);
        $sum2 = $data[0];
        array_shift($data);
        foreach ($data as $value) {
            $sum2 = $sum2 ^ $value;
        }
        return $sum2 == $sum1;
    }

    /**
     * 注释:格式化日志
     * 创建者:JSL
     * 时间:2023/06/29 029 下午 02:22
     * @param $log
     * @return string
     */
    public static function formattingLog($log): string
    {
        return is_array($log) && count($log) > 0 ? implode("\n\r", $log) : '报文未解析';
    }
}